﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using WeiXinSDK.Common;
using WeiXinSDK.MP.Model;
using WeiXinSDK.MP.Model.Enum;

namespace WeiXinSDK.MP
{
	/// <summary>
	/// 公众号接口
	/// 读取本地token缓存,调用失败时
	/// 从中心服务器获取再次调用,再次调用失败时,调用服务器刷新
	/// 使用异步或者方法拦截实现
	/// </summary>
	public class Api : IApi
	{
		private string AppId { get { return Config.AppSettings["WeiXinAppId"]; } }

		private string Secret { get { return Config.AppSettings["WeiXinSecret"]; } }

		private string CenterService { get { return Config.AppSettings["WeiXinTokenService"]; } }

		private static AccessTokenModel _token;

		public AccessTokenModel Token
		{
			get
			{
				if (_token == null || _token.TimeOut)
				{
					lock ("WeiXinSDK.MP.Api.Token")
					{
						if (_token == null || _token.TimeOut)
						{//TODO: 改为从中心服务器获取token
							_token = GetAccessToken().Result;
						}
					}
				}
				return _token;
			}
		}


		#region 基础接口

		/// <summary> 获取有效accessToken </summary>
		public async Task<AccessTokenModel> GetAccessToken()
		{
			return await HttpClient.GetAsJson<AccessTokenModel>(ApiUrl.GetToken.FormatExt(AppId, Secret));
		}

		public async Task<AccessTokenModel> GetAccessTokenByCenterService()
		{
			return await HttpClient.GetAsJson<AccessTokenModel>(CenterService);
		}

		public async Task<ServiceIpList> GetCallBackIp()
		{
			return await HttpClient.GetAsJson<ServiceIpList>(ApiUrl.GetCallBackIp.FormatExt(Token.AccessToken));
		}

		#endregion

		#region 发送消息

		#region 客服接口 TODO: 无法测试API文档有问题 删除接口问题有问题无法开发

		/// <summary> 创建客服账号 </summary>
		public async Task<ResponseModel> KFAccountCreate(string account, string nickName, string password)
		{
			return await HttpClient.PostAsJson<ResponseModel>(ApiUrl.KFAccountCreate.FormatExt(Token.AccessToken),
				new { kf_account = account, nickname = nickName, password = password.MD5Default() });
		}


		/// <summary> 修改客服账号 </summary>
		public async Task<ResponseModel> KFAccountUpdate(string account, string nickName, string password)
		{
			return await HttpClient.PostAsJson<ResponseModel>(ApiUrl.KFAccountUpdate.FormatExt(Token.AccessToken), new { kf_account = account, nickname = nickName, password });
		}

		/// <summary> 删除客服账号,暂时无法开发 </summary>
		public async Task<ResponseModel> KFAccountDelete(string account)
		{
			throw new NotImplementedException();
		}

		/// <summary> 设置客服账号头像 </summary>
		public async Task<ResponseModel> KFAccountUploadHeadImg(string account, string file)
		{
			var response = await HttpClient.PostFile(ApiUrl.KFAccountUploadHeadImg.FormatExt(Token.AccessToken, account), file);
			return response.JsonDeserialize<ResponseModel>();
		}

		/// <summary> 获取所有客服账号 </summary>
		public async Task<KFAccountList> GetKFList()
		{
			return await HttpClient.GetAsJson<KFAccountList>(ApiUrl.KFAccountGetList.FormatExt(Token.AccessToken));
		}


		/// <summary> 发送客服消息
		/// 当用户主动发消息给公众号 48小时内不限制发送次数
		/// </summary>
		public async Task<ResponseModel> SendMessage(CustomMessageBaseModel message)
		{
			return await HttpClient.PostAsJson<ResponseModel>(ApiUrl.SendCustomMessage.FormatExt(Token.AccessToken), message);
		}

		#endregion


		#region 高级群发接口

		/// <summary>
		/// 上传多图文消息,用于群发多图文消息
		/// </summary>
		public async Task<MediaUploadResponeModel> UploadNews(ArticleMedia news)
		{
			return await HttpClient.PostAsJson<MediaUploadResponeModel>(ApiUrl.UploadNews.FormatExt(Token.AccessToken), news);
		}


		/// <summary> 群发给分组用户 </summary>
		public async Task<MassResponseModel> Mass2Group(MassMessage2GroupModel msg)
		{
			return await HttpClient.PostAsJson<MassResponseModel>(ApiUrl.Mass2Group.FormatExt(Token.AccessToken), msg);
		}

		/// <summary> 群发给用户列表 </summary>
		public async Task<MassResponseModel> Mass2UserList(MassMessage2UserListModel msg)
		{
			return await HttpClient.PostAsJson<MassResponseModel>(ApiUrl.Mass2UserList.FormatExt(Token.AccessToken), msg);
		}

		/// <summary> 删除群发消息 </summary>
		/// <remarks>请注意，只有已经发送成功的消息才能删除删除消息只是将消息的图文详情页失效，已经收到的用户，还是能在其本地看到消息卡片。 另外，删除群发消息只能删除图文消息和视频消息，其他类型的消息一经发送，无法删除。</remarks>
		public async Task<ResponseModel> DeleteMass(string msgId)
		{
			return await HttpClient.PostAsJson<ResponseModel>(ApiUrl.DeleteMass.FormatExt(Token.AccessToken), new { msg_id = msgId });
		}

		/// <summary>  查询群发消息发送状态【订阅号与服务号认证后均可用】 </summary>
		public async Task<MassStatus> GetMassStatus(string msgId)
		{
			return await HttpClient.PostAsJson<MassStatus>(ApiUrl.GetMassStatus.FormatExt(Token.AccessToken), new { msg_id = msgId });
		}

		/// <summary> 预览接口【订阅号与服务号认证后均可用】 </summary>
		/// <param name="openId">接收消息用户对应该公众号的openid</param>
		/// <param name="msgtype">群发的消息类型，图文消息为mpnews，文本消息为text，语音为voice，音乐为music，图片为image，视频为video</param>
		/// <param name="content">用于群发的消息的media_id或发送文本消息时文本的内容</param>
		/// <returns></returns>
		public async Task<MassResponseModel> MassPreview(string openId, string msgtype, string content)
		{
			object param = null;
			switch (msgtype)
			{
				case "mpnews":
					param = new { touser = openId, mpnews = new { media_id = content }, msgtype };
					break;
				case "text":
					param = new { touser = openId, text = new { content }, msgtype };
					break;
				case "voice":
					param = new { touser = openId, voice = new { media_id = content }, msgtype };
					break;
				case "image":
					param = new { touser = openId, image = new { media_id = content }, msgtype };
					break;
				case "mpvideo":
					param = new { touser = openId, mpvideo = new { media_id = content }, msgtype };
					break;
				default:
					throw new ArgumentException("msgtype的值只能为mpnews,text,voice,music,image,video中的一个", "msgtype");
			}
			return await HttpClient.PostAsJson<MassResponseModel>(ApiUrl.MassPreview.FormatExt(Token.AccessToken), param);
		}

		#endregion


		#region 模板消息接口

		public async Task<ResponseModel> SetIndustry(Industry industry1, Industry industry2)
		{
			return await HttpClient.PostAsJson<ResponseModel>(ApiUrl.SetIndustry.FormatExt(Token.AccessToken),
				new
				{
					industry_id1 = ((int)industry1).ToString(),
					industry_id2 = ((int)industry2).ToString()
				});
		}
		public async Task<TemplateModel> AddTemplate(string templateShortId)
		{
			return await HttpClient.PostAsJson<TemplateModel>(ApiUrl.AddTemplate.FormatExt(Token.AccessToken),
				new { template_id_short = templateShortId });
		}

		public async Task<MsgReseponse> SendTemplateMessage(TemplateMsgModel msg)
		{
			return await HttpClient.PostAsJson<MsgReseponse>(ApiUrl.SendTemplateMessage.FormatExt(Token.AccessToken), msg);
		}

		#endregion

		/// <summary> 获取自动回复规则 </summary>
		public async Task<AutoReplyInfoModel> GetAutoReplyInfo()
		{
			return await HttpClient.GetAsJson<AutoReplyInfoModel>(ApiUrl.GetAutoReplyInfo.FormatExt(Token.AccessToken));
		}

		#endregion

		#region 素材管理

		/// <summary> 新增临时素材
		/// 
		/// </summary>
		public async Task<MediaUploadResponeModel> MediaUpload(string file, MediaType type)
		{
			var json = await HttpClient.PostFile(ApiUrl.UploadMedia.FormatExt(Token.AccessToken, type.ToString().ToLower()), file);
			return json.JsonDeserialize<MediaUploadResponeModel>();
		}

		/// <summary> 获取临时素材
		/// 请注意，视频文件不支持https下载，调用该接口需http协议。
		/// </summary>
		public async Task<MediaFileModel> MediaDownLoad(string mediaId)
		{
			var response = await HttpClient.GetResponse(ApiUrl.DownLoadMedia.FormatExt(Token.AccessToken, mediaId));
			if (response.Headers.Any(m => m.Key == "Content-Type" && m.Value.Any(s => s == "text/plain")))
			{
				return await response.Content.ReadAsStringAsync().ContinueWith(m => m.Result.JsonDeserialize<MediaFileModel>());
			}
			return await response.Content.ReadAsByteArrayAsync().ContinueWith(m => new MediaFileModel { File = m.Result });
		}

		/// <summary> 新增其他类型永久素材 </summary>
		public async Task<AddMaterialResponseModel> AddMaterial(string file, MediaType type, string title = null, string introduction = null)
		{
			new NotImplementedException();
			return new AddMaterialResponseModel { };
		}

		/// <summary> 新增永久图文素材 </summary>
		public async Task<AddMaterialResponseModel> AddNewsMaterial(NewsMaterialModel news)
		{
			return await HttpClient.PostAsJson<AddMaterialResponseModel>(ApiUrl.AddNewsMaterial.FormatExt(Token.AccessToken), news);
		}




		#endregion

	}
}
